#include "data/editor_data.hpp"

#include <sqrat.h>
#include <sqstdblob.h>
#include <sqstddatetime.h>
#include <sqstdio.h>
#include <sqstdmath.h>
#include <sqstdstring.h>
#include <sqstdsystem.h>

#include "scripting/extra/info_api.hpp"
#include "utils/app_utils.hpp"
#include "utils/date_utils.hpp"
#include "utils/log.hpp"
#include "utils/path_utils.hpp"
#include "utils/shell_utils.hpp"
#include "sql/sql_data_extensions.hpp"

using namespace Sqrat;

void RegisterEditorType(HSQUIRRELVM vm)
{
    assert(vm != nullptr);

    RootTable table(vm);

    // std types
    sqstd_seterrorhandlers(vm);
    sqstd_register_bloblib(vm);
    sqstd_register_datetimelib(vm);
    sqstd_register_iolib(vm);
    sqstd_register_mathlib(vm);
    sqstd_register_stringlib(vm);
    sqstd_register_systemlib(vm);

    // clipboard function
    table.Func(_SC("CopyText"), &::CopyText);

    // version
    table.Func(_SC("AppVersionStr"), &::GetAppVersionText);
    table.Func(_SC("AppVersionInfo"), &::GetAppVersionInfo);
    table.Func(_SC("AppVersionCode"), &::GetAppVersionCode);
    table.Func(_SC("DataVersionStr"), &::GetDataVersion);
    table.Func(_SC("DataVersionCode"), &::GetDataVersionCode);

    // path utils
    table.Func(_SC("TempPath"), &GetTempFilePath);
    table.Func(_SC("AssetPath"), &GetAssetsPath);
    table.Func(_SC("DataPath"), &GetDataPath);

    // date utils
    table.Func(_SC("Yestoday"),&GetYesterday);
    table.Func(_SC("Today"),&GetToday);
    table.Func(_SC("Tomorrow"),&GetTomorrow);

    // info dialog
    table.Func(_SC("ShowInfo"), [](const char* msg) { SendInfo(msg); });
    table.Func(_SC("ShowWarning"), [](const char* msg) { SendWarning(msg); });
    table.Func(_SC("ShowError"), [](const char* msg) { SendError(msg); });
    table.Func(_SC("ShowProgress"), [](bool show) { ShowProgressDialog(show); });

    // logging
    table.Func(_SC("LogD"), [](const char* msg){log_printf("<script>", 1, LOG_LEVEL_DEBUG, "%s", msg);});
    table.Func(_SC("LogI"), [](const char* msg){log_printf("<script>", 1, LOG_LEVEL_INFO, "%s", msg);});
    table.Func(_SC("LogW"), [](const char* msg){log_printf("<script>", 1, LOG_LEVEL_WARN, "%s", msg);});
    table.Func(_SC("LogE"), [](const char* msg){log_printf("<script>", 1, LOG_LEVEL_ERROR, "%s", msg);});

    // status message
    table.Func(_SC("Notification"), [](const char *msg, double duration_ms) { SendNotification(msg, duration_ms); });

    // shell utils
    table.Func(_SC("ChooseFile"), &ChooseFile);
    table.Func(_SC("ChooseFiles"), &ChooseFiles);
    table.Func(_SC("SaveFile"), &SaveFile);
    table.Func(_SC("PickFoler"), &PickFolder);
    table.Func(_SC("ShowLogs"), &ShowLogFileContent);

    // app utils
    table.Func(_SC("CreateWork"), &CreateWorkItem);
    table.Func(_SC("CreateWorkWithNote"), &CreateWorkItemWithNote);
    table.Func(_SC("ShowStatistics"), &ShowStatistics);

    // data ext
    table.Func(_SC("GetIssueProjectDesc"), sql_data_ext.get_issue_project_desc);

    Class<WorkItem> c_work_item{ vm, _SC("WorkItem") };
    c_work_item
        .ConstVar(_SC("create_date"), &WorkItem::create_date)
        .ConstVar(_SC("comment"), &WorkItem::comment)
        .ConstVar(_SC("hour"), &WorkItem::hour)
        .ConstVar(_SC("note"), &WorkItem::note)
        .ConstVar(_SC("issue"), &WorkItem::issue_id)
        .ConstVar(_SC("act"), &WorkItem::act_id);
    table.Bind(_SC("WorkItem"), c_work_item);

    Class<Tag> c_tag{ vm, _SC("Tag") };
    c_tag
        .ConstVar(_SC("tag_name"), &Tag::tag_name)
        .ConstVar(_SC("tag_color"), &Tag::tag_color)
        .ConstVar(_SC("tag_level"), &Tag::tag_level);
    table.Bind(_SC("Tag"), c_tag);

    // TODO: std::vector<Tag>
    VectorRegisterHelper<Tag>::bind(table, "TagVec");

    Class<ItemNode> c_node{ vm, _SC("ItemNode") };
    c_node
        .ConstVar(_SC("item"), &ItemNode::item)
        .GlobalProp(_SC("tags"), [](const ItemNode *v) { return &v->item_tags; });
    table.Bind(_SC("ItemNode"), c_node);

    // TODO: std::list<ItemNode>
    ListRegisterHelper<ItemNode>::bind(table, "ItemNodeList");

    Class<DayLevelNode> c_dln{ vm, _SC("DayLevelNode") };
    c_dln
        .Func(_SC("load"), &DayLevelNode::LoadInnerData)
        .GlobalProp(_SC("key"), [](const DayLevelNode* v) { return v->child_key; })
        .GlobalProp(_SC("title"), [](const DayLevelNode* v) { return v->title; })
        .GlobalProp(_SC("children"), [](const DayLevelNode* v) { return &v->children; });
    table.Bind(_SC("DayLevelNode"), c_dln);

    // TODO: std::list<DayLevelNode>
    ListRegisterHelper<DayLevelNode>::bind(table, "ItemNodeList");

    Class<MonthLevelNode> c_mln{ vm, _SC("MonthLevelNode") };
    c_mln
        .Func(_SC("load"), &MonthLevelNode::LoadInnerData)
        .GlobalProp(_SC("key"), [](const MonthLevelNode* v) { return v->child_key; })
        .GlobalProp(_SC("title"), [](const MonthLevelNode* v) { return v->title; })
        .GlobalProp(_SC("children"), [](const MonthLevelNode* v) { return &v->children; });
    table.Bind(_SC("MonthLevelNode"), c_mln);

    // TODO: std::list<MonthLevelNode>
    ListRegisterHelper<MonthLevelNode>::bind(table, "ItemNodeList");

    Class<YearLevelNode> c_yln{ vm, _SC("YearLevelNode") };
    c_yln
        .Func(_SC("load"), &YearLevelNode::LoadInnerData)
        .GlobalProp(_SC("key"), [](const YearLevelNode* v) { return v->child_key; })
        .GlobalProp(_SC("title"), [](const YearLevelNode* v) { return v->title; })
        .GlobalProp(_SC("children"), [](const YearLevelNode* v) { return &v->children; });
    table.Bind(_SC("YearLevelNode"), c_yln);
}
